/**
 * @file TEST_macro_overload.c
 * @author Linquan  
 * @brief 对 macro_overload.h头文件中 宏函数的测试
 * @version 1.0
 * @date 2024-06-07
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#include "app_config.h"
#if TEST_MACRO_OVERLOAD


#include <stdio.h>
#include <stdint.h>
// #include <stdarg.h>
#include "macro_overload.h"



/*********************************3、单一函数，传入可变参数，具备默认参数**************************************************/

/* 定义函数的默认输入参数值 */ 
#define DEFAULT_A   0
#define DEFAULT_B   0
#define DEFAULT_C   0

/*
    定义具体实现不同参数数量的宏, 宏的数量 = 函数的输入参数数量+1
    宏名格式： 函数名_输入参数的个数 
    宏内容：输入参数以及默认输入的参数
*/
#define function_name0()        function_name(DEFAULT_A, DEFAULT_B, DEFAULT_C )
#define function_name1(a)       function_name(a, DEFAULT_B, DEFAULT_C )
#define function_name2(a, b)    function_name(a, b, DEFAULT_C)
#define function_name3(a,b,c)   function_name(a, b, c)

/* 原始函数 */
static void function_name( int a,int b,int c)
{

    printf("FUNC_MUTI_ARG :%d ,%d,%d\n",a,b,c);
}


void Test_single_func_muti_arg()
{
    printf("3、single_func_muti_arg: \n");
   FUNC_MUTI_ARG(function_name);
   FUNC_MUTI_ARG(function_name,1,3,4);
   FUNC_MUTI_ARG(function_name,4,4);
}

/**********************4、 函数重载 根据输入参数的数量，选择对应的函数 *******************************/

void RELOAD_FUC_NAME(device_print,1)(int a)
{
    printf("111 %d \n",a);
}

void RELOAD_FUC_NAME(device_print,2)(int a, int b)
{
    printf("222 %d ,%d\n",a,b);
}

void RELOAD_FUC_NAME(device_print,3)(int a, int b, int c)
{
    printf("333 %d,%d,%d \n",a,b,c);
}

void RELOAD_FUC_NAME(device_print,4)(int a,int b,int c,int d)
{
    printf("444 %d,%d,%d %d \n",a,b,c,d);
}

void Test_func_reload()
{
    printf("4、func_reload_test: \n");

    FUNC_RELOAD(device_print,1);
    FUNC_RELOAD(device_print,1,2);
    FUNC_RELOAD(device_print,1,2,3);
    FUNC_RELOAD(device_print,1,2,3,4);
    //FUNC_RELOAD(device_print,1,2,3,4,5); //erro
}

/********************** 5、using 重载 ******************************/

void Test_using()
{
    printf(" 6、using_test :\r\n");

    /* 1、只有一个参数 ，声明一个变量 */
    printf(" --------1、only declear------ \r\n");
    using(  int a = 1 ) 
    {
        printf("        In -only declear- Body a=%d \r\n", ++a);
    }

    /* 2、有两个参数，声明一个变量、一个离开时执行的函数 */
    printf(" -------- 2、declear and leave_func ------ \r\n");
    using(  int a = 2,               
            printf("        ========= On Leave =======\r\n")         
         ) 
    {
        printf("        In -declear and leave_func- Body a=%d b \r\n", ++a);
    }

    /* 3.1、有三个参数，声明一个变量、一个进入时执行的函数，一个退出时执行的函数 */
    printf(" -------- 3.1、enter_func、declear and leave_func ------ \r\n");
    using(  int a = 3,
            printf("        ========= On Enter =======\r\n"), 
            printf("        ========= On Leave =======\r\n")         
         ) 
    {
        printf("        In - enter_func、declear and leave_func-Body a=%d \r\n", ++a);
    } 


    /* 3.2、有三个参数，声明一个变量、一个进入时执行的函数，
            但是退出时执行的函数不填写，使用逗号分隔 */
    printf(" -------- 3.2、declear、enter_func、but no leave_func ------ \r\n");
     using(  int a = 4,
            printf("        ========= On Enter =======\r\n"),  
           NULL /* 退出时执行的函数没有，但是这个参数位置要存在 */                  
         ) 
    {
        printf("        In -declear、enter_func、but no leave_func-Body a=%d \r\n", ++a);
    } 


    /* 4、有四个参数，声明两个同类型的变量、一个进入时执行的函数，一个退出时执行的函数 */
    printf(" -------- 4、 declear_1、declear_2、enter_func、leave_func ------ \r\n");
    using(  int a = 4, 
             b = 9,
            printf("        ========= On Enter =======\r\n"),       
            printf("        ========= On leave =======\r\n")           
         ) 
    {
        printf("        In -declear、enter_func、but no leave_func-Body \n\t a=%d \r\n", ++a);
        printf("        In -declear、enter_func、but no leave_func-Body \n\t b=%d \r\n", ++b);
    } 


    /* 5、有四个参数，声明两个同类型的变量、进入时需要执行的内容，退出时需要执行的内容 */
     printf(" -------- 5、 declear_1、declear_2、many enter_func、lots of leave_func ------ \r\n");
        using(  
                /* 第一个、第二个参数 */     
                int64_t a = 0,  b  = 5,
                /* 第三个参数：进入时执行的内容 */ 
                {
                    printf("        Here is enter function, let a = 0X20 .b = 0X10\n");   
                    a = 0X20;   
                    b = 0X10;              
                                
                }, 
                /* 第四个参数，退出时执行的内容。注意前边的逗号 */                                                              \
                {                                                                                                                                
                    printf("       Here is leave function, the value: a = %ld,b = %ld\r\n",      
                            (long)a, (long)b);                                         
                }                                                       
            )
            {
                /* 循环体内执行的内容，没有循环体的内容，会报错 */
                printf("        using body \n");
            }

}




/*********************** 6、foreach遍历数组 ，**************************
 *********************** 7、reverse_foreach逆向遍历数组，****************
 *********************** 8、ptr_foreach 指针遍历后number个元素***********
 */

typedef struct example_lv0_t {
    uint32_t    wA;
    uint16_t    hwB;
    uint8_t     chC;
    uint8_t     chID;
} example_lv0_t;

example_lv0_t s_tItem[8] = {
    {.chID = 9},
    {.chID = 1},
    {.chID = 2},
    {.chID = 3},
    {.chID = 4},
    {.chID = 5},
    {.chID = 6},
    {.chID = 7},
};


void Test_foreach()
{
    printf(" 7、 foreach_test: \r\n");

    /* 1、正序遍历数组元素 */
    printf(" ----foreach from 0 -> 7 by arry------ \r\n");

    /* 1.1、传入两个元素，使用指针：_ 打印遍历内容 */
    foreach(example_lv0_t, s_tItem)
    {
        printf("Processing item with ID by two parament = %d\r\n", _->chID);
    }

    /* 1.2、传入三个元素，使用指针：ptItem 打印遍历内容。ptItem无需提前定义 */
    foreach(example_lv0_t, s_tItem, ptItem) 
    {
        printf("Processing item with ID by three parament  = %d\r\n", ptItem->chID);
    }
    

    /* 2、逆序遍历数组元素 */
    printf(" ----reverse foreach from 7 -> 0 ------ \r\n");

    /* 2.1、传入两个元素，使用指针：_ 打印遍历内容 */
     reverse_foreach(example_lv0_t, s_tItem) 
    {
        printf("Processing item with ID by “_”= %d\r\n", _->chID);
    }

    /* 2.2、传入三个元素，使用指针：ptItem 打印遍历内容 ，ptItem无需提前定义 */
    reverse_foreach(example_lv0_t, s_tItem, ptItem) 
    {
        printf("Processing item with ID = %d\r\n", ptItem->chID);
    }


    /* 3、使用指针，遍历后num个元素 */
    printf(" ---- foreach eight value by ptr  ------ \r\n");

    example_lv0_t *arry_ptr = s_tItem ;
    
    /* 3.1、传入两个元素，使用指针：arry_ptr 打印遍历内容  */
    ptr_foreach( arry_ptr,8)
    {
         printf("foreach ID by point:\"arry_ptr\" with two parament = %d\r\n", arry_ptr->chID);
    }
    /* 这种方式，会改变原指针arry_ptr的值 */
    printf("the arry_ptr is = %d,it has changed \r\n", arry_ptr->chID);
    
    /* 重新指向数组起始位置 */
    arry_ptr = s_tItem ;
    /* 3.2、传入三个元素，使用指针：_ 打印遍历内容 */
    ptr_foreach(example_lv0_t, arry_ptr,8)
    {
         printf("foreach ID by point:\"_\" with tree parament = %d\r\n", _->chID);
    }
    /* 这种方式，不改变原指针arry_ptr的值  */
    printf("the arry_ptr is = %d,it doesn't change \r\n", arry_ptr->chID);
}



/********************** 10、with局部指针声明 ******************************/

/* ！！！ 注意这是个函数类型，不是函数指针，不是（*p_with_function） ！！！ */
typedef void (p_with_function)(void);

void with_test_function()
{
    printf("with function is here \n");
}

void Test_with_code()
{
    int a = 3;

    /* 1、 用指针 _ 指向a的地址 */
    with(int,&a)
    {
        printf(" _ addr  = %p \n", _);
        printf(" _  = %d \n", *_);
    }
    
   /* 2、定义一个ptr_value指针，指向a的地址。  ptr_value 不需要预先定义 */
    with(int,&a, ptr_value)
    {
        printf(" ptr_value addr  = %p \n", ptr_value);
        printf(" ptr_value  = %d \n", *ptr_value);
    }


   /* 3、定义一个ptr_func指针，指向p_with_function类型的函数，ptr_func 不需要预先定义 
        这里 p_with_function 是一个函数类型，不是一个函数指针
   */
    with(p_with_function,&with_test_function, ptr_func)
    {
        ptr_func();
    }
}


/********************** 11、递归宏，递减 ，最小值0 ******************************/

#define evt_list(name)  CONNECT_N(evt_, name, _list)

// 根据类型 使用宏定义类型对应的编号，使用递归宏完成遍历
#define OverviewAlarmEvt                  0
#define OverviewFireRecomAlarmEvt         1
#define OverviwOtherEvt                   2

/**> 根据序号生成对应变量 */
uint8_t  evt_list(OverviewAlarmEvt          );
uint8_t  evt_list(OverviewFireRecomAlarmEvt );
uint8_t  evt_list(OverviwOtherEvt           );

/**
 * @brief 声明一个宏函数，其中存放需要递归调用的内容，传入递归层数n，可以根据层数选择对应的变量
 * 
 */
#define FUNC_ACT(n)  {                          \
                        evt_list(n) = n+1;      \
                        printf("Recursion level: %d, evt_list(n): %d \n", n, evt_list(n));\
                    }

/**
 * @brief 遍历是从最大的值开始递减遍历，这里传入的数应该是上边变量编号的最大值
 * 
 */
void recursive_macro_test_function()
{
    #define RECURSIVE_2     2  /**> 这里2 代表遍历的第一个值，终点值为0，遍历三次 */ 
     RECURSIVE_MACRO(FUNC_ACT, RECURSIVE_2);
}   



void macro_overload_test()
{
    /* 1、 宏参数计算 */
    printf("1、meroc args number:%d \n",VA_ARGS_COUNT(33,33,a,3,4,6));

    /* 2、参数连接宏 */
    printf("2.1 args connect merooc :%#X \n",HEX_VALUE(F3));
    printf("2.2 args connect 2 :%d \n",CONNECT_N(2,3));

    /* 3、单一函数输入指定默认参数 */
    Test_single_func_muti_arg();

    /* 4、函数重载 */
    Test_func_reload();

    /* 5、 using 重载*/
    Test_using();

    /* 6、foreach遍历数组 ，*********************
     * 7、reverse_foreach逆向遍历数组，**********
     * 8、ptr_foreach 指针遍历后number个元素****
     * */
    Test_foreach();

     /* 10、局部指针声明 */
    Test_with_code();

    /* 11、 递归宏 递归执行宏函数 */
    recursive_macro_test_function();
}
EXPORT_Lv6_APP_SINGLE(macro_overload_test, NULL);

#endif

